package com.study.mybatis.executor.statement;

import com.study.mybatis.executor.Executor;
import com.study.mybatis.executor.ExecutorException;
import com.study.mybatis.executor.parameter.ParameterHandler;
import com.study.mybatis.executor.resultset.ResultSetHandler;
import com.study.mybatis.mapping.MappedStatement;
import com.study.mybatis.session.Configuration;
import com.study.mybatis.session.ResultHandler;
import com.study.mybatis.type.TypeHandlerRegistry;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author yuantongqin
 * 2021/7/31
 **/
public abstract class BaseStatementHandler implements StatementHandler{
    /** #{}正则匹配 */
    private static Pattern param_pattern = Pattern.compile("#\\{([^\\{\\}]*)\\}");


    protected final Configuration configuration;
    protected final TypeHandlerRegistry typeHandlerRegistry;
    protected final ResultSetHandler resultSetHandler;
    protected final ParameterHandler parameterHandler;

    protected final Executor executor;
    protected final MappedStatement mappedStatement;


    protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, ResultHandler resultHandler) {
        this.configuration = mappedStatement.getConfiguration();
        this.executor = executor;
        this.mappedStatement = mappedStatement;

        this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();

        this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject);
        this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler);
    }


    @Override
    public Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException {
        String sql = this.mappedStatement.getSql();
        // 通过连接
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(parseSymbol(sql));
            statement.setQueryTimeout(transactionTimeout);
            return statement;
        } catch (SQLException e) {
            closeStatement(statement);
            throw e;
        } catch (Exception e) {
            closeStatement(statement);
            throw new ExecutorException("Error preparing statement.  Cause: " + e, e);
        }
    }

    private static String parseSymbol(String source)
    {
        source = source.trim();
        Matcher matcher = param_pattern.matcher(source);
        return matcher.replaceAll("?");
    }

    @Override
    public ParameterHandler getParameterHandler() {
        return parameterHandler;
    }


    protected void closeStatement(Statement statement) {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                // ignore
            }
        }
    }

}
